#2.7 Implement an environment for an x by m rectangular room, where each square has a 5% chance
#of containing dirt, and n and m are chosen at random from the range 8 to 15, inclusive.

#2.8 Design and implement a pure reflex agent for the environment of Exercise 2.7, ignoring
#the requirement of returning home, and measure its performance. Explain why it is impossible
#to have a reflex agent that returns homeland shuts itself off. Speculate on what the best possible
#reflex agent could do. What prevents a reflex agent from doing very well?

#It is impossible to have a reflex agent that returns home and shuts itself off, becuase to be able
#to get home, it would need to be able to have a goal (this type of behavior is reserved for, of
#course, Goal-based agents. Even if the agent reacted to being 'home' by turning itself off, it is
#not guaranteed that the agent will ever get there.

#The best possible reflex agent would be one that uses its sensors to recognize its environment 
#so that it can react accordingly at every iteration. The worst reaction agent, I would imagine, 
#would be one that could not sense its environment at all, to the point that it could never react to 
#anything.

#Reflex agents do not do very well in many situations, for obvious reasons. First of all, most agents 
#are created for a certain reason or job, but reflex agents have no goal or objective. Also, they are
#not very efficient. This is becuase they do not compare all possible actions and weigh the outcome.
#They, instead, react one way all the time no matter how 'good' the reaction is.

import breve
import time

class Controller(breve.Control):
	def __init__(self):
		breve.Control.__init__(self)
		self.setBackgroundColor(breve.vector())
		self.enableLighting()
		env = Room(breve.randomExpression(breve.vector(7, 0, 7)) + breve.vector(8, 0, 8), breve.randomExpression(5), 10)
		env.placeBot(ReflexBot())
		self.startTime = time.clock()
				
	def iterate(self):
		breve.Control.iterate(self)
		self.updateNeighbors()	
	
class ReflexBot(breve.Mobile):
	def __init__(self):
		breve.Mobile.__init__(self)
		self.direction = breve.vector(0, 0, 0)
		self.setShape(breve.createInstances(breve.Sphere, 1).initWith(5))
		self.setColor(breve.vector(1, 0, 0))
		self.handleCollisions('Wall', 'wallCollision')
		self.setNeighborhoodSize(7)
		self.enablePhysics()
		self.changeDirection()		
	
	def iterate(self):
		breve.Mobile.iterate(self)
		neighborList = self.getNeighbors()
		if len(neighborList) > 0:
			neighbor = neighborList.pop()
			if isinstance(neighbor, DirtPatch):
				self.dirtPercept(neighbor)
		
	def dirtPercept(self, patch):
		color = patch.getColor()
		if color.__getattr__('x') > 0:
			self.setVelocity(patch.getLocation() - self.getLocation())
			color = breve.vector(
				patch.getColor().__getattr__('x') - .01, 
				patch.getColor().__getattr__('y') - .01, 
				patch.getColor().__getattr__('z') - .01)
			patch.setColor(color)
		else: self.changeDirection()	
		
	def wallCollision(self):
		self.changeDirection()

	def changeDirection(self):
		self.setVelocity(breve.randomExpression(breve.vector(50, 0, 50)) - breve.vector(25, 0, 25))	
	
class Room(breve.Real):
	def __init__(self, dim, patchCount, unit):
		breve.Real.__init__(self)
		self.unit = unit
		self.width = dim.__getattr__('x') * unit
		self.height = dim.__getattr__('z') * unit
		self.width -= self.width % unit
		self.height -= self.height % unit
		self.getController().pointCamera(breve.vector(self.width / 2, 0, -self.height / 2), breve.vector(0, 100, self.height))
		self.getController().moveLight(breve.vector(self.width / 2, 10, -self.height / 2))
		
		for x in range(0, self.width / unit):
			Wall(breve.vector(x * unit + 5, 5, 0), breve.vector(unit, 10, .1))
			Wall(breve.vector(x * unit + 5, 5, -self.height), breve.vector(unit, 10, .1))
		
		for z in range(0, self.height / unit):
			Wall(breve.vector(0, 5, -z * unit - 5), breve.vector(.1, 10, unit))
			Wall(breve.vector(self.width, 5, -z * unit - 5), breve.vector(.1, 10, unit))

		for z in range(0, self.height / unit):
			for x in range(0, self.width / unit):
				Ground(breve.vector(x * unit + 5, 0, -z * unit - 5), breve.vector(unit, .1, unit))
			
		#Ground(breve.vector(self.width / 2, 0, -self.height / 2), breve.vector(self.width, .1, self.height))
		
	def placeBot(self, bot):
		bot.move(breve.vector(self.width / 2, 9, -self.height / 2))

	def getWidth(self): return self.width
	def getHeight(self): return self.height
	def getUnit(self): return self.unit
	
class Obstruction(breve.Stationary):
	def __init__(self, position, dimension, color):
		breve.Stationary.__init__(self)
		self.setTexture(-1)
		self.setShape(breve.createInstances(breve.Cube, 1).initWith(dimension))
		self.setColor(color)
		self.move(position)
	
class Wall(Obstruction):
	def __init__(self, position, dimension):
		Obstruction.__init__(self, position, dimension, breve.vector(1.0, 1.0, 1.0))
		self.setBitmapTransparency(0.5)	
		
class Ground(Obstruction):
	def __init__(self, position, dimension):
		Obstruction.__init__(self, position, dimension, breve.vector(0.0, 0.3, 0.0))
		self.setBitmapTransparency(0.5)

class DirtPatch(Obstruction):
	def __init__(self, position, dimension):
		Obstruction.__init__(self, position, dimension, breve.vector(0.5, 0.5, 0.0))
		self.setBitmapTransparency(0.5)
		self.dirty = True
		
	def iterate(self):
		if self.dirty:
			if self.getColor().__getattr__('x') <= 0:
				self.flag()
			
	def flag(self):
		self.dirty = False
		self.getController().stopTime = time.clock()
		print "Clean Time:"
		print self.getController().stopTime - self.getController().startTime
	
Controller()